package test.game;



import ija.model.CheckersModel;
import ija.model.GameModel;
import java.lang.reflect.*;

//import org.junit.AfterClass;
//import org.junit.BeforeClass;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

import ija.model.basis.*;
import ija.model.figures.*;
import ija.model.players.LocalPlayer;
import ija.model.players.Player;
import ija.model.players.RemotePlayer;
import ija.model.types.Color;
import ija.model.types.Direction;

/**
 * Homework2: uloha c. 2 z IJA
 * Trida testujici implementaci zadani 2. ukolu.
 */
public class TestGame {

    @Before
    public void setUp() {

    }

    @After
    public void tearDown() {

    }

    
    
    /** Test zakladnich vlastnosti trid Desk a Position */
    @Test
    public void testDeskPosition() {
        
        System.out.println("Test zakladnich vlastnosti desky - prevzato z ukolu IJA");
        Desk d1 = new Desk(8);

        Position p1 = d1.getPositionAt('h', 5);
        Position p2 = p1.nextPosition(-1, 2);
        Position p3 = d1.getPositionAt('g', 7);
        assertEquals("Posun z pozice h5 o (-1,2) = pozice g7", p2, p3);

        Position p10 = d1.getPositionAt('h', 5);
        assertEquals("Spravna pozice h5", p10, p1);
        assertNull("Pozice h5 je prazda (bez figurky).", p10.getFigure());

        Position p11 = d1.getPositionAt('h', 12);
        assertNull("Pozice h12 neexistuje.", p11);
        System.out.println("Ziskani pozic z desky - OK \n");
    }

    
    /** Test zakladnich vlastnosti trid Position ve vztahu k Figure */
    @Test
    public void testPositionFigure() {
        
        System.out.println("Test pozic prevzato z IJA");
        Desk d1 = new Desk(8);
        Position p1 = d1.getPositionAt('d', 2);
        Position p2 = d1.getPositionAt('d', 6);

        Figure f1 = new Piece(p1, Color.BLACK, Direction.FORWARD);
        Figure f2 = new Piece(p2, Color.BLACK, Direction.FORWARD);

        assertEquals("Na pozici d2 je pesec-vpred.", p1.getFigure(), f1);

        Figure f10 = p1.removeFigure();
        Figure f11 = p2.putFigure(f10);
        assertEquals("Na pozici d6 byl vlozen pesec f1.", f10, f1);
        assertEquals("Na pozici d6 je pesec f1.", p2.getFigure(), f1);
        assertEquals("Z pozice d6 byl odstranen pesec f2.", f11, f2);
        assertNull("Pozice d2 je prazdna", p1.getFigure());
        
        System.out.println("Test pozic ok \n");
    }


    /** Test inicializace GameModelu */
    @Test
    public void testGameModelInit() {
        // Vypis inicializace desky
        System.out.println("Test inicializace hraci desky - vypis stavu desky");
        CheckersModel gamemodel1 = new CheckersModel();
        gamemodel1.initGame(Color.BLACK);
        gamemodel1.getDesk().printOccupy();
        System.out.println("=============================================\n");// Vypis inicializace desky

    }
    
    /** Test figurek reprezentujici pesce (vpred a vzad) */
    @Test
    public void testPiece() {
        
        System.out.println("Test pohybu pesce");
        Desk d1 = new Desk(8);

        Figure f1 = new Piece(d1.getPositionAt('d', 2), Color.BLACK, Direction.FORWARD);
        Position p1 = f1.getPosition();

        Figure f2 = d1.getPositionAt('d', 2).getFigure();
        assertEquals("Na pozici d2 je pesec-vpred.", f2, f1);

        Figure f21 = d1.getFigureAt('d', 2);
        assertEquals("Na pozici d2 je pesec-vpred", f21, f1);
        Figure f22 = d1.getFigureAt('d', 5);
        assertNull("Pozice d5 je prazda (bez figurky).", f22);

        
        // Test pohybu pesce-vpred
        assertTrue("Pesec muze jit dopredu doprava", f1.canMove(p1.nextPosition(1, 1)));
        assertTrue("Pesec muze jit dopredu doleva", f1.canMove(p1.nextPosition(-1, 1)));
        
        assertFalse("Pesec nesmi dozadu doprava", f1.canMove(p1.nextPosition(1, -1)));
        assertFalse("Pesec nesmi dozadu doleva", f1.canMove(p1.nextPosition(-1, -1)));
        assertFalse("Pesec nesmi doprava", f1.canMove(p1.nextPosition(1, 0)));
        assertFalse("Pesec nesmi doleva", f1.canMove(p1.nextPosition(-1, 0)));
        assertFalse("Pesec nesmi dopredu", f1.canMove(p1.nextPosition(0, 1)));
        assertFalse("Pesec nesmi dozadu", f1.canMove(p1.nextPosition(0, -1)));
        assertFalse("Pesec nesmi o dve po diagonale vpravo", f1.canMove(p1.nextPosition(2, 2)));
        assertFalse("Pesec nesmi o dve po diagonale vlevo", f1.canMove(p1.nextPosition(-2, 2)));
        assertFalse("Pesec nesmi zustat stat", f1.canMove(p1.nextPosition(0, 0)));
        System.out.println("Test metody canMove() pesce vpred - OK");
        
        assertTrue("Pohyb na e3", f1.move(p1.nextPosition(1, 1)));
        assertEquals("Pesec se posunul na e3", f1.getPosition(), d1.getPositionAt('e', 3));
        assertNull("Pozice e5 ma byt prazdna", d1.getPositionAt('d', 2).getFigure());
        System.out.println("Pohyb pesce vpred z d2 na e3 - OK");
        
        // Test pohybu pesce-vzad
        Figure fBack = new Piece(d1.getPositionAt('e', 5), Color.WHITE, Direction.BACK);
        Position pBack = fBack.getPosition();
        assertTrue("Pesec muze jit dozadu doprava", fBack.canMove(pBack.nextPosition(1, -1)));
        assertTrue("Pesec muze jit dozadu doleva", fBack.canMove(pBack.nextPosition(-1, -1)));
        
        assertFalse("Pesec nesmi dopredu doprava", fBack.canMove(pBack.nextPosition(1, 1)));
        assertFalse("Pesec nesmi dopredu doleva", fBack.canMove(pBack.nextPosition(-1, 1)));
        assertFalse("Pesec nesmi doprava", fBack.canMove(pBack.nextPosition(1, 0)));
        assertFalse("Pesec nesmi doleva", fBack.canMove(pBack.nextPosition(-1, 0)));
        assertFalse("Pesec nesmi dopredu", fBack.canMove(pBack.nextPosition(0, 1)));
        assertFalse("Pesec nesmi dozadu", fBack.canMove(pBack.nextPosition(0, -1)));
        assertFalse("Pesec nesmi o dve po diagonale vpravo", fBack.canMove(pBack.nextPosition(2, -2)));
        assertFalse("Pesec nesmi o dve po diagonale vlevo", fBack.canMove(pBack.nextPosition(-2, -2)));
        assertFalse("Pesec nesmi zustat stat", fBack.canMove(pBack.nextPosition(0, 0)));
        System.out.println("Test metody canMove() pesce vzad - OK");
        
        assertTrue("Pohyb na f4", fBack.move(pBack.nextPosition(1, -1)));
        assertEquals("Pesec se posunul na f4", fBack.getPosition(), d1.getPositionAt('f', 4));
        assertNull("Pozice e5 ma byt prazdna", d1.getPositionAt('e', 5).getFigure());
        assertEquals("Cilova pozice obsahuje odkaz na pesce", fBack, d1.getPositionAt('f', 4).getFigure());
        System.out.println("Pohyb pesce vzad z e5 na f4 - OK");
        
        
        // Test skoku
        CheckersFigure cfForward = (CheckersFigure) f1;
        CheckersFigure cfForward2 = new Piece(d1.getPositionAt('d', 4), Color.BLACK, Direction.FORWARD);
        CheckersFigure cfBack = (CheckersFigure) fBack;
        CheckersFigure cfBack2 = new Piece(d1.getPositionAt('g', 3), Color.WHITE, Direction.BACK);
        
        Position pForward = cfForward.getPosition();
        pBack = cfBack.getPosition();
        
        assertNull("Nelze preskakovat vlastni pesce-vpred-cerna(e3xc5)", cfForward.canJump(d1.getPositionAt('e', 7)));
        assertNull("Nelze preskakovat vlastni pesce-vzad-bila(f4xh2)", cfBack.canJump(d1.getPositionAt('h', 2)));
        
        assertEquals("Pesec na e3 muze preskocit pesce na f4", cfForward.canJump(pForward.nextPosition(2, 2)), cfBack.getPosition());
        assertEquals("Pesec na e3 muze preskocit pesce na f4", cfBack.canJump(pBack.nextPosition(-2, -2)), cfForward.getPosition());
        System.out.println("Test metody canJump() pesce - OK");
        
        assertTrue("Skok e3 na g5", cfForward.jump(pForward.nextPosition(2, 2)));
        assertNull("Na e3 neni figurka (pozice pred skokem)", d1.getPositionAt('e', 3).getFigure());
        assertNull("Na pozici preskocene figurky neni byt figurka", pBack.getFigure());
        assertNull("Preskocena figurka nesmi byt na zadne pozici", cfBack.getPosition());
        assertEquals("Na pozici g5 ma byt figurka (cilova pozice skoku)", d1.getPositionAt('g', 5).getFigure(), cfForward);
        assertEquals("Figurka, ktera provadela skok odkazuje na cilovou pozici", cfForward.getPosition(), d1.getPositionAt('g', 5));
        System.out.println("Skok pesce z e3 na g5 - OK");
        

    }

    /** Test hraci figurky Dama */
    @Test
    public void testQueen() {
        System.out.println("Test damy");
        Desk d = new Desk();
        
        Figure f = new Queen(d.getPositionAt('d', 4), Color.WHITE);
        Position p = f.getPosition();
        
        // Test pohybu vpred
        assertTrue("Dama se muze pohybovat o vice poli vpred vpravo (d4-g7)", f.canMove(p.nextPosition(3, 3)));
        assertTrue("Dama se muze pohybovat o vice poli vpred vlevo (d4-a7)", f.canMove(p.nextPosition(-3, 3)));
        assertTrue("Dama se muze pohybovat o vice poli vzad vpravo (d4-g1)", f.canMove(p.nextPosition(3, -3)));
        assertTrue("Dama se muze pohybovat o vice poli vzad vlevo (d4-a1)", f.canMove(p.nextPosition(-3, -3)));
    
        assertFalse("Dama nesmi vpravo", f.canMove(p.nextPosition(3, 0)));
        assertFalse("Dama nesmi vlevo", f.canMove(p.nextPosition(-3, 0)));
        assertFalse("Dama nesmi nahoru", f.canMove(p.nextPosition(0, 3)));
        assertFalse("Dama nesmi dolu", f.canMove(p.nextPosition(0, -3)));
        assertFalse("Dama nesmi zustat stat", f.canMove(p));
        
        System.out.println("Test Queen.canMove() - OK");
        
        assertTrue("Dama se presouva na h8", f.move(p.nextPosition(4, 4)));
        assertNull("Misto po presunu damy musi zustat prazdne (d4)", d.getPositionAt('d', 4).getFigure());
        assertEquals("Dama musi byt na cilove pozici (h8)", d.getPositionAt('h', 8).getFigure(), f);
        assertEquals("Dama odkazuje na cilovou pozici", f.getPosition(), d.getPositionAt('h', 8));
        
        System.out.println("Pohyb damy z d4 na h8 (o 4) - OK");
        
        // Test skoku
        CheckersFigure cf = (CheckersFigure)f;
        p = cf.getPosition();
        Figure jf = new Piece(d.getPositionAt('d', 4), Color.BLACK, Direction.FORWARD);
        
        assertEquals("Dama muze preskocit soupere tesne za nej", cf.canJump(p.nextPosition(-5, -5)), jf.getPosition());
        assertEquals("Dama muze preskocit soupere o vice pozic", cf.canJump(p.nextPosition(-7, -7)), jf.getPosition());
        
        System.out.println("Test canJump() - OK");
        
        assertTrue("Dama provedla skok (h8xa1)", cf.jump(p.nextPosition(-7, -7)));
        assertNull("Po skoku musi byt puvodni misto damy prazdne (h8)", d.getPositionAt('h', 8).getFigure());
        assertNull("Po skoku musi zmizet preskocena figurka (d4)", d.getPositionAt('d', 4).getFigure());
        assertNull("Odstranena figurka nesmi mit prirazenu pozici", jf.getPosition());
        assertEquals("Dama se musi presunout na cilovou pozici", d.getPositionAt('a', 1).getFigure(), cf);
        assertEquals("Dama musi odkazovat na cilovou pozici", cf.getPosition(), d.getPositionAt('a', 1));
        
        System.out.println("Test skoku z h8 na a1 (souper na d4) - OK");
        
        jf = new Piece(d.getPositionAt('d', 4), Color.BLACK, Direction.FORWARD);
        Figure stopJump = new Piece(d.getPositionAt('e', 5), Color.BLACK, Direction.FORWARD);
        p = cf.getPosition();
        
        assertEquals("Nelze preskocit figurku, za kterou je dalsi figurka - hned za figurku", cf.canJump(p.nextPosition(4,4)), null);
        assertEquals("Nelze preskocit figurku, za kterou je dalsi figurka - vice mist za figurku", cf.canJump(p.nextPosition(6,6)), null);
        
        assertTrue("Posuneme stopovaci figurku na f6", stopJump.move(stopJump.getPosition().nextPosition(1, 1)));
        assertNull("Nelze preskocit figurku, za kterou je dalsi figurka - hned za figurku", cf.canJump(p.nextPosition(5,5)));
        assertNull("Nelze preskocit figurku, za kterou je dalsi figurka - vice mist za figurku", cf.canJump(p.nextPosition(7,7)));
        System.out.println("Test skoku co nelze provest (za figurkou stop figurka) - OK");
        System.out.println();
    }
    
    
    /** Test nasazovani damy GameModelem */
    @Test
    public void testGameModelSetQueen() {
        
        System.out.println("Test nasazeni damy pescem");
        CheckersModel gm2 = new CheckersModel();
        Position pq = gm2.getDesk().getPositionAt('h', 8);
        Queen q = new Queen(pq, Color.BLACK);
        pq.putFigure(q);
        
        // Test nasazeni damy damou
        assertFalse("Nelze nasazovat tam, kde neni figurka", gm2.canSetQueen(gm2.getDesk().getPositionAt('b', 8)));
        assertFalse("Damou nelze nasadit damu - nahore", gm2.canSetQueen(pq));
        assertTrue("Posunuti damy na druhy konec sachovnice", q.move(pq.nextPosition(-7, -7)));        
        pq = q.getPosition();
        assertFalse("Damou nelze nasadit damu - dole", gm2.canSetQueen(pq));
        
        // Test chybneho nasazeni damy pescem
        Position p1 = gm2.getDesk().getPositionAt('c', 1);
        p1.putFigure(new Piece(p1, Color.BLACK, Direction.FORWARD));
        assertFalse("Nelze nasadit pescem na jeho domaci pozici - dole", gm2.canSetQueen(p1));
        
        p1 = gm2.getDesk().getPositionAt('d', 8);
        p1.putFigure(new Piece(p1, Color.WHITE, Direction.BACK));
        assertFalse("Nelze nasadit pescem na jeho domaci pozici - nahore", gm2.canSetQueen(p1));
        
        // Test spravneho nasazeni damy
        Position p2 = gm2.getDesk().getPositionAt('e', 1);
        Figure fBack = new Piece(p2, Color.WHITE, Direction.BACK);
        p2.putFigure(fBack);
        p1 = gm2.getDesk().getPositionAt('b', 8);
        Figure fForward = new Piece(p1, Color.BLACK, Direction.FORWARD);
        p1.putFigure(fForward);
        assertTrue("Figurku na cilove horni pozici lze nasadit", gm2.canSetQueen(p1));
        assertTrue("Figurku na cilove dolni pozici lze nasadit", gm2.canSetQueen(p2));
        
        assertTrue("Nasazeni figurky - dole", gm2.setQueen(p2));
        assertTrue("Nasazena figurka musi byt dama", p2.getFigure() instanceof Queen);
        assertEquals("Nasazena dama musi mit stejnou barvu", p2.getFigure().getColor(), fBack.getColor());
        assertNull("Zmeneny pesec nesmi byt na zadne pozici", fBack.getPosition());
        
        assertTrue("Nasazeni figurky - nahore", gm2.setQueen(p1));
        assertTrue("Nasazena figurka musi byt dama", p1.getFigure() instanceof Queen);
        assertEquals("Nasazena dama musi mit stejnou barvu", p1.getFigure().getColor(), fForward.getColor());      
        assertNull("Zmeneny pesec nesmi byt na zadne pozici", fForward.getPosition());
        
        System.out.println("Test nasazeni damy - OK");
        
        System.out.println();
        
    }
    
    /** Test pohybu figurkami GameModelem */
    @Test
    public void testGameModelMove() {
        CheckersModel gm = new CheckersModel();
        Position pf = gm.getDesk().getPositionAt('d', 6);
        CheckersFigure f = new Piece(pf, Color.BLACK, Direction.FORWARD);
        
        // Bezny pohyb
        assertTrue("Pohyb pescem vpred", gm.move(pf, pf.nextPosition(1, 1)));
        assertNull("Zdrojova pozice prazdna", pf.getFigure());
        assertEquals("Cilova pozice obsazena", f.getPosition(), gm.getDesk().getPositionAt('e', 7));
        assertTrue("Cilova pozice pesec", pf.nextPosition(1, 1).getFigure() instanceof Piece);
        
        // Chybny pohyb - proti smeru figurky
        pf = f.getPosition();
        assertFalse("Pohyb pescem v opacnem smeru zakazan", gm.move(pf, pf.nextPosition(-1, -1)));
        assertEquals("Pesec po nevalidnim pohybu zustal na miste", gm.getDesk().getFigureAt(pf.getColumnChar(), pf.getRowNumber()), f);
        assertNull("Pozice kam se mela figurka chybne pohnout zustala prazdna", pf.nextPosition(-1, -1).getFigure());
        
        // Nasazeni pri pohybu do cile
        pf = f.getPosition();
        assertTrue("Pohyb pescem vpred", gm.move(pf, pf.nextPosition(1, 1)));
        assertNull("Zdrojova pozice prazdna", pf.getFigure());
        assertNull("Pesec uz neni na sachovnici. Zmenil se v damu", f.getPosition());
        assertTrue("Cilova pozice obsazena damou", gm.getDesk().getPositionAt('f', 8).getFigure() instanceof Queen);
        
        System.out.println("Test pohybu pomoci GameModelu - OK");
        System.out.println();
    }
    
    /** Test skoku provadeneho GameModelem */
    @Test
    public void testGameModelJump() {
        CheckersModel gm = new CheckersModel();
        
        Position pq = gm.getDesk().getPositionAt('a', 1);
        Queen q = new Queen(pq, Color.BLACK);
        
        Position p1 = gm.getDesk().getPositionAt('d', 4);
        Piece f1 = new Piece(p1, Color.WHITE, Direction.FORWARD);
        
        Position p2 = gm.getDesk().getPositionAt('e', 5);
        Piece f2 = new Piece(p2, Color.BLACK, Direction.BACK);
        
        // Pesec skace pesce
        assertTrue("Pesec skace pesce (d4xf6)", gm.jump(p1, p1.nextPosition(2, 2)));
        assertNull("Po skoku misto skakajiciho prazdne", p1.getFigure());
        assertNull("Po skoku misto preskoceneho prazdne", p2.getFigure());
        assertEquals("Po skoku obsazena cilova pozice", p1.nextPosition(2, 2).getFigure(), f1);
        assertNull("Preskoceny pesec neni na sachovnici", f2.getPosition());
        assertEquals("Pozice skakajiciho pesce odpovida cilove pozici skoku", f1.getPosition(), p1.nextPosition(2, 2));
        
        // Dama skace pesce
        p1 = f1.getPosition();
        assertTrue("Dama skace pesce (a1xh8)", gm.jump(pq, pq.nextPosition(7, 7)));
        assertNull("Po skoku misto skakajiciho prazdne", pq.getFigure());
        assertNull("Po skoku misto preskoceneho prazdne", p1.getFigure());
        assertEquals("Po skoku obsazena cilova pozice", pq.nextPosition(7, 7).getFigure(), q);
        assertNull("Preskoceny pesec neni na sachovnici", f1.getPosition());
        assertEquals("Pozice skakajici damy odpovida cilove pozici skoku", q.getPosition(), pq.nextPosition(7, 7));
        
         System.out.println("Test skoku pomoci GameModelu - OK");
        System.out.println();
    }
    
    /** Test hracu */
    @Test
    public void testPlayers() {
        
        System.out.println("Test hracu");
        GameModel gm = new CheckersModel();
        Player p1 = new LocalPlayer("Lokalni hrac", Color.BLACK, Direction.FORWARD);
        Player p2 = new RemotePlayer("Vzdaleny hrac", Color.BLACK, Direction.FORWARD, RemotePlayer.ConnectType.INITIATOR, "0.0.0.0", 15);
        
        //Pridani hracu
        gm.setPlayer(0, p1);
        gm.setPlayer(1, p2);
        assertEquals("Ziskani hrace 1", gm.getPlayer(0), p1);
        assertEquals("Ziskani hrace 2", gm.getPlayer(1), p2);
        assertEquals("Automaticky aktivni hrac je 0", gm.getActivePlayer(), p1);
        
        // Nastaveni aktivniho hrace na hrace p2 - id 1
        gm.activatePlayer(1);
        assertEquals("Aktivovani hrace 1", p2, gm.getActivePlayer());
        
        // Test nextPlayer
        gm.nextPlayer();
        assertEquals("Po hraci 1 aktivni hrac 0", p1, gm.getActivePlayer());
        gm.nextPlayer();
        assertEquals("Po hraci 0 aktivni hrac 1", p2, gm.getActivePlayer());
        
        // Test chyb
        gm = new CheckersModel();
        
        assertFalse("Nelze pridat hrace se zapornym id", gm.setPlayer(-1, p2));
        assertFalse("Nelze pridat hrace s id > 1", gm.setPlayer(2, p2));
        assertNull("Nelze ziskat hrace s id > 1", gm.getPlayer(2));
        assertNull("Nelze ziskat hrace se zapornym id", gm.getPlayer(-1));
        assertFalse("Nelze aktivovat zaporneho hrace", gm.activatePlayer(-1));
        assertFalse("Nelze aktivovat hrace s id > 1", gm.activatePlayer(2));
        
        // Pokud nejsou hraci pridani, meli bychom vzdy ziskat null
        assertNull("Ziskani hrace 0, ktery ale neni vlozen", gm.getPlayer(0));
        assertNull("Ziskani hrace 1, ktery ale neni vlozen", gm.getPlayer(1));
        assertNull("Ziskani aktivniho hrace, zadny hrac vlozen", gm.getActivePlayer());
        
         System.out.println("Test nastaveni hracu, zmeny aktivniho hrace a ziskavani info o hracich - OK");
        System.out.println();
        
    }
    
    
    

}
